package concurrency;

import static java.util.concurrent.locks.LockSupport.parkNanos;

import java.util.concurrent.TimeUnit;

import javax.swing.SwingUtilities;

/**
 * Basic thread blocking primitives for creating locks and other synchronization classes.
 * 
 * @see java.util.concurrent.locks.LockSupport
 * @author Mykhaylo Adamovych
 */
public class LockSupport {
    /**
     * Disables the current thread for thread scheduling purposes.
     * 
     * @param condition
     * @author Mykhaylo Adamovych
     */
    public static void parkUntil(Condition condition) {
        parkUntil(10, TimeUnit.DAYS.toMillis(365), condition);
    }

    /**
     * Disables the current thread for thread scheduling purposes. Condition implies to be obligatory. Otherwise it should be found condition to resume or even
     * not start to wait. It is wrong to use timeout as a synchronisation mechanism, set timeout to be fail fast and easy to diagnose deadlock issues.
     * 
     * @param checkIntervalMs
     * @param timeoutMs
     * @param condition
     * @author Mykhaylo Adamovych
     */
    public static void parkUntil(long checkIntervalMs, long timeoutMs, Condition condition) {
        if (SwingUtilities.isEventDispatchThread())
            throw new IllegalAccessError();
        long staleThreshold = System.currentTimeMillis() + timeoutMs;
        while (!condition.isSatisfied()) {
            if (System.currentTimeMillis() > staleThreshold)
                throw new Error("Timed out after " + timeoutMs);
            parkNanos(TimeUnit.MILLISECONDS.toNanos(checkIntervalMs));
        }
    }

    /**
     * Cannot be instantiated.
     */
    private LockSupport() {
    }
}
